`include "defines.v"

module id(
    input wire rst,
    //from id 
    input wire[`InstBus] inst_i,
    input wire[`InstAddrBus] InstAddr_i,

    //from regs
    input wire[`RegBus] rdata1_i,
    input wire[`RegBus] rdata2_i,

    //from csr_reg
    input wire[`RegBus] rdata_csr_i,

    //to ex and clint
    output reg[`InstBus] Inst_o,
    output reg[`InstAddrBus] InstAddr_o,
    
    //only to ex
    output reg[`RegBus] rdata1_o,
    output reg[`RegBus] rdata2_o,
    output reg[`RegBus] rdata_csr_o,

    
    //to regs
    output reg[`RegAddrBus] raddr1_o,
    output reg[`RegAddrBus] raddr2_o,
    //to csr_reg
    output reg[`MemAddrBus] raddr_csr_o,

    //to rib
    output reg rib_req,

    //to IFU
    output reg jalr_predicition_o,
    output reg[`RegBus] rdata_to_ifu_o

);

    wire[6:0] opcode = inst_i[6:0];
    wire[2:0] funct3 = inst_i[14:12];
    wire[6:0] funct7 = inst_i[31:25];
    wire[4:0] rd = inst_i[11:7];
    wire[4:0] rs1 = inst_i[19:15];
    wire[4:0] rs2 = inst_i[24:20];  
    wire[31:0] csr = {21'b0, inst_i[31:21]};
    
    always @ (*)
        begin
            if (rst == `RstEnable)
                begin
                    Inst_o = `ZeroWord;
                    InstAddr_o = `ZeroWord;
                    rdata1_o = `ZeroWord;
                    rdata2_o = `ZeroWord;
                    raddr1_o = `ZeroReg;
                    raddr2_o = `ZeroReg;
                    raddr_csr_o = `ZeroWord;
                    rib_req = `RIB_NREQ;
                    jalr_predicition_o = `PredictionDisable;
                    rdata_to_ifu_o = `ZeroWord;


                end 
            else
                begin
                    Inst_o = inst_i;
                    InstAddr_o = InstAddr_i;
                    rdata1_o = rdata1_i;
                    rdata2_o = rdata2_i;
                    rdata_csr_o = rdata_csr_i;
                    jalr_predicition_o = `PredictionDisable;
                    rdata_to_ifu_o = `ZeroWord;
                    case(opcode)
                        `INST_TYPE_I:
                            begin
                                raddr_csr_o = `ZeroWord;
                                rib_req = `RIB_NREQ;
                                case(funct3)
                                `INST_ADDI, `INST_SLTI, `INST_SLTIU, `INST_XORI, `INST_ORI, `INST_ANDI, `INST_SLLI, `INST_SRI:
                                    begin
                                        raddr1_o = rs1;
                                        raddr2_o = `ZeroReg;
                                        
                                    end
                                default:
                                    begin
                                        raddr1_o = `ZeroReg;
                                        raddr2_o = `ZeroReg;
                                    end
                                endcase
                            end
                        `INST_TYPE_L:
                            begin
                                raddr_csr_o = `ZeroWord;
                                rib_req = `RIB_REQ;
                                case(funct3)
                                `INST_LB,`INST_LH, `INST_LW, `INST_LBU, `INST_LHU:
                                    begin
                                        raddr1_o = rs1;
                                        raddr2_o = `ZeroReg;
                                    end
                                default:
                                    begin
                                        raddr1_o = `ZeroReg;
                                        raddr2_o = `ZeroReg;
                                    end
                                endcase
                            end
                        `INST_FENCE:
                            begin
                                raddr1_o = `ZeroReg;
                                raddr2_o = `ZeroReg;
                                raddr_csr_o = `ZeroWord;
                                rib_req = `RIB_NREQ;
                            end
                        `INST_TYPE_S:
                            begin
                                raddr_csr_o = `ZeroWord;
                                rib_req = `RIB_REQ;
                                case(funct3)
                                `INST_SB, `INST_SH, `INST_SW:
                                    begin
                                        raddr1_o = rs1;
                                        raddr2_o = rs2;
                                    end
                                default:
                                    begin
                                        raddr1_o = `ZeroReg;
                                        raddr2_o = `ZeroReg;
                                    end
                                endcase
                            end
                        `INST_TYPE_R_M:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                if (funct7 == 7'b0100_000 || funct7 == 7'b0000_000)
                                    case(funct3)
                                    `INST_ADD_SUB,`INST_SLL, `INST_SLT, `INST_SLTU, `INST_XOR, `INST_SR, `INST_OR, `INST_AND:
                                        begin
                                            raddr1_o = rs1;
                                            raddr2_o = rs2;
                                        end
                                    default:
                                        begin
                                            raddr1_o = `ZeroReg;
                                            raddr2_o = `ZeroReg;
                                        end
                                    endcase
                                else if (funct7 == 7'b0000_001)
                                    case (funct3)
                                    `INST_MUL, `INST_MULH, `INST_MULHSU, `INST_MULHU,`INST_DIV,`INST_DIVU,`INST_REM, `INST_REMU:
                                        begin
                                            raddr1_o = rs1;
                                            raddr2_o = rs2;
                                        end
                                    default:
                                        begin
                                            raddr1_o = `ZeroReg;
                                            raddr2_o = `ZeroReg;
                                        end
                                    endcase
                            end
                        `INST_JAL:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                raddr1_o = `ZeroReg;
                                raddr2_o = `ZeroReg;
                            end
                        `INST_JALR:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                raddr1_o = rs1;
                                raddr2_o = `ZeroReg;
                                //prediciton
                                if (rs1 != 5'b0)
                                    begin
                                        jalr_predicition_o = `PredictionEnable;
                                        rdata_to_ifu_o = rdata1_i;
                                    end
                            end
                        `INST_TYPE_B:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                case(funct3)
                                    `INST_BEQ, `INST_BNE, `INST_BLT, `INST_BGE, `INST_BLTU, `INST_BGEU:
                                        begin
                                            raddr1_o = rs1;
                                            raddr2_o = rs2;
                                        end
                                    default:
                                        begin
                                            raddr1_o = `ZeroReg;
                                            raddr2_o = `ZeroReg;
                                        end
                                endcase
                            end
                        `INST_LUI:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                raddr1_o = `ZeroReg;
                                raddr2_o = `ZeroReg;
                            end
                        `INST_AUIPC:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                raddr1_o = `ZeroReg;
                                raddr2_o = `ZeroReg;
                            end
                        `INST_CSR:
                            begin
                                rib_req = `RIB_NREQ;
                                case(funct3)
                                `INST_CSRRW,`INST_CSRRS,`INST_CSRRC:begin
                                    raddr1_o = rs1;
                                    raddr2_o = `ZeroReg;
                                    raddr_csr_o = csr;
                                end
                                `INST_CSRRWI,`INST_CSRRSI,`INST_CSRRCI:begin
                                    raddr1_o = `ZeroReg;
                                    raddr2_o = `ZeroReg;
                                    raddr_csr_o = csr;
                                end
                                endcase
                            end
                        default:
                            begin
                                rib_req = `RIB_NREQ;
                                raddr_csr_o = `ZeroWord;
                                raddr1_o = `ZeroReg;
                                raddr2_o = `ZeroReg;
                            end
                    endcase
                end
        end



endmodule